  <!DOCTYPE html>
  <html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="generator" content="pandoc" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
    <title>GTK 4 tutorial</title>
    <style>
      code{white-space: pre-wrap;}
      span.smallcaps{font-variant: small-caps;}
      span.underline{text-decoration: underline;}
      div.column{display: inline-block; vertical-align: top; width: 50%;}
      div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
      ul.task-list{list-style: none;}
      pre{overflow: visible;}
      pre > code.sourceCode { white-space: pre; position: relative; }
      pre > code.sourceCode > span { display: inline-block; line-height: 1.25; }
      pre > code.sourceCode > span:empty { height: 1.2em; }
      code.sourceCode > span { color: inherit; text-decoration: inherit; }
      div.sourceCode { margin: 1em 0; }
      pre.sourceCode { margin: 0; }
      @media screen {
      div.sourceCode { overflow: auto; }
      }
      @media print {
      pre > code.sourceCode { white-space: pre-wrap; }
      pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; }
      }
      pre.numberSource code
        { counter-reset: source-line 0; }
      pre.numberSource code > span
        { position: relative; left: -4em; counter-increment: source-line; }
      pre.numberSource code > span > a:first-child::after
        { content: counter(source-line);
          position: relative; left: -1em; text-align: right; vertical-align: baseline;
          border: none; display: inline-block;
          -webkit-touch-callout: none; -webkit-user-select: none;
          -khtml-user-select: none; -moz-user-select: none;
          -ms-user-select: none; user-select: none;
          padding: 0 4px; width: 4em;
          color: #aaaaaa;
        }
      pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa;  padding-left: 4px; }
      div.sourceCode
        {   }
      @media screen {
      pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; }
      }
      code span.al { color: #ff0000; font-weight: bold; } /* Alert */
      code span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */
      code span.at { color: #7d9029; } /* Attribute */
      code span.bn { color: #40a070; } /* BaseN */
      code span.bu { } /* BuiltIn */
      code span.cf { color: #007020; font-weight: bold; } /* ControlFlow */
      code span.ch { color: #4070a0; } /* Char */
      code span.cn { color: #880000; } /* Constant */
      code span.co { color: #60a0b0; font-style: italic; } /* Comment */
      code span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */
      code span.do { color: #ba2121; font-style: italic; } /* Documentation */
      code span.dt { color: #902000; } /* DataType */
      code span.dv { color: #40a070; } /* DecVal */
      code span.er { color: #ff0000; font-weight: bold; } /* Error */
      code span.ex { } /* Extension */
      code span.fl { color: #40a070; } /* Float */
      code span.fu { color: #06287e; } /* Function */
      code span.im { } /* Import */
      code span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */
      code span.kw { color: #007020; font-weight: bold; } /* Keyword */
      code span.op { color: #666666; } /* Operator */
      code span.ot { color: #007020; } /* Other */
      code span.pp { color: #bc7a00; } /* Preprocessor */
      code span.sc { color: #4070a0; } /* SpecialChar */
      code span.ss { color: #bb6688; } /* SpecialString */
      code span.st { color: #4070a0; } /* String */
      code span.va { color: #19177c; } /* Variable */
      code span.vs { color: #4070a0; } /* VerbatimString */
      code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */
      div.sourceCode { margin: 10px; padding: 16px 10px 8px 10px; border: 2px solid silver; background-color: ghostwhite; overflow-x:scroll}
      pre:not(.sourceCode) { margin: 10px; padding: 16px 10px 8px 10px; border: 2px solid silver; background-color: ghostwhite; overflow-x:scroll}
      table {margin-left: auto; margin-right: auto; border-collapse: collapse; border: 1px solid;}
      th {padding: 2px 6px; border: 1px solid; background-color: ghostwhite;}
      td {padding: 2px 6px; border: 1px solid;}
      img {display: block; margin-left: auto; margin-right: auto;}
      figcaption {text-align: center;}
    </style>
  </head>
  <body style="padding-top: 70px;">
    <div class="container">
    <nav class="navbar fixed-top navbar-expand-lg navbar-dark bg-primary">
      <div class="container-fluid">
        <span class="navbar-brand">Gtk4 tutorial</span>
        <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
          <span class="navbar-toggler-icon"></span>
        </button>
        <div class="collapse navbar-collapse" id="navbarSupportedContent">
          <ul class="navbar-nav me-auto mb-2 mb-lg-0">
            <li class="nav-item">
<a class="nav-link" href="index.html">Home</a>
</li>

            <li class="nav-item">
<a class="nav-link" href="sec21.html">Prev: section21</a>
</li>

            <li class="nav-item">
<a class="nav-link" href="sec23.html">Next: section23</a>
</li>

          </ul>
        </div>
      </div>
    </nav>
<h1 id="gtkdrawingarea-and-cairo">GtkDrawingArea and Cairo</h1>
<p>If you want to draw dynamically on the screen, like an image window
of gimp graphics editor, the GtkDrawingArea widget is the most suitable
widget. You can freely draw or redraw an image in this widget. This is
called custom drawing.</p>
<p>GtkDrawingArea provides a cairo drawing context so users can draw
images by using cairo functions. In this section, I will explain:</p>
<ol type="1">
<li>Cairo, but only briefly</li>
<li>GtkDrawingArea, with a very simple example.</li>
</ol>
<h2 id="cairo">Cairo</h2>
<p>Cairo is a set of two dimensional graphical drawing functions (or
graphics library). There are a lot of documents on <a
href="https://www.cairographics.org/">Cairo’s website</a>. If you aren’t
familiar with Cairo, it is worth reading the <a
href="https://www.cairographics.org/tutorial/">tutorial</a>.</p>
<p>The following is an introduction to the Cairo library and how to use
it. First, you need to know about surfaces, sources, masks,
destinations, cairo context and transformations.</p>
<ul>
<li>A surface represents an image. It is like a canvas. We can draw
shapes and images with different colors on surfaces.</li>
<li>The source pattern, or simply source, is like paint, which will be
transferred to destination surface by cairo functions.</li>
<li>The mask describes the area to be used in the copy;</li>
<li>The destination is a target surface;</li>
<li>The cairo context manages the transfer from source to destination,
through mask with its functions; For example, <code>cairo_stroke</code>
is a function to draw a path to the destination by the transfer.</li>
<li>A transformation can be applied before the transfer completes. The
transformation which is applied is called affine, which is a
mathematical term meaning transofrmations that preserve straight lines.
Scaling, rotating, reflecting, shearing and translating are all examples
of affine transformations. They are mathematically represented by matrix
multiplication and vector addition. In this section we don’t use it,
instead we will only use the identity transformation. This means that
the coordinates in the source and mask are the same as the coordinates
in destination.</li>
</ul>
<figure>
<img src="image/cairo.png" alt="Stroke a rectangle" />
<figcaption aria-hidden="true">Stroke a rectangle</figcaption>
</figure>
<p>The instruction is as follows:</p>
<ol type="1">
<li>Create a surface. This will be the destination.</li>
<li>Create a cairo context with the surface, the surface will be the
destination of the context.</li>
<li>Create a source pattern within the context.</li>
<li>Create paths, which are lines, rectangles, arcs, texts or more
complicated shapes in the mask.</li>
<li>Use a drawing operator such as <code>cairo_stroke</code> to transfer
the paint in the source to the destination.</li>
<li>Save the destination surface to a file if necessary.</li>
</ol>
<p>Here’s a simple example program that draws a small square and saves
it as a png file. The path of the file is
<code>src/misc/cairo.c</code>.</p>
<p>@@<span class="citation" data-cites="include">@include</span>
misc/cairo.c @@@</p>
<ul>
<li>1: Includes the header file of Cairo.</li>
<li>6: <code>cairo_surface_t</code> is the type of a surface.</li>
<li>7: <code>cairo_t</code> is the type of a cairo context.</li>
<li>8-10: <code>width</code> and <code>height</code> are the size of
<code>surface</code>. <code>square_size</code> is the size of a square
to be drawn on the surface.</li>
<li>13: <code>cairo_image_surface_create</code> creates an image
surface. <code>CAIRO_FORMAT_RGB24</code> is a constant which means that
each pixel has red, green and blue data, and each data point is an 8
bits number (for 24 bits in total). Modern displays have this type of
color depth. Width and height are in pixels and given as integers.</li>
<li>14: Creates cairo context. The surface given as an argument will be
the destination of the context.</li>
<li>18: <code>cairo_set_source_rgb</code> creates a source pattern,
which in this case is a solid white paint. The second to fourth
arguments are red, green and blue color values respectively, and they
are of type float. The values are between zero (0.0) and one (1.0), with
black being given by (0.0,0.0,0.0) and white by (1.0,1.0,1.0).</li>
<li>19: <code>cairo_paint</code> copies everywhere in the source to
destination. The destination is filled with white pixels with this
command.</li>
<li>21: Sets the source color to black.</li>
<li>22: <code>cairo_set_line_width</code> set the width of lines. In
this case, the line width is set to be two pixels and will end up that
same size. (It is because the transformation is identity. If the
transformation isn’t identity, for example scaling with the factor
three, the actual width in destination will be six (2x3=6) pixels.)</li>
<li>23: Draws a rectangle (square) on the mask. The square is located at
the center.</li>
<li>24: <code>cairo_stroke</code> transfer the source to destination
through the rectangle in the mask.</li>
<li>27: Outputs the image to a png file <code>rectangle.png</code>.</li>
<li>28: Destroys the context. At the same time the source is
destroyed.</li>
<li>29: Destroys the surface.</li>
</ul>
<p>To compile this, change your current directory to
<code>src/misc</code> and type the following.</p>
<pre><code>$ gcc `pkg-config --cflags cairo` cairo.c `pkg-config --libs cairo`</code></pre>
<figure>
<img src="image/rectangle.png" alt="rectangle.png" />
<figcaption aria-hidden="true">rectangle.png</figcaption>
</figure>
<p>See the <a href="https://www.cairographics.org/">Cairo’s website</a>
for further information.</p>
<h2 id="gtkdrawingarea">GtkDrawingArea</h2>
<p>The following is a very simple example.</p>
<p>@@<span class="citation" data-cites="include">@include</span>
misc/da1.c @@@</p>
<p>The function <code>main</code> is almost same as before. The two
functions <code>app_activate</code> and <code>draw_function</code> are
important in this example.</p>
<ul>
<li>22: Creates a GtkDrawingArea instance.</li>
<li>25: Sets a drawing function of the widget. GtkDrawingArea widget
uses the function to draw the contents of itself whenever its necessary.
For example, when a user drag a mouse pointer and resize a top-level
window, GtkDrawingArea also changes the size. Then, the whole window
needs to be redrawn. For the information of
<code>gtk_drawing_area_set_draw_func</code>, see <a
href="https://docs.gtk.org/gtk4/method.DrawingArea.set_draw_func.html">Gtk
API Reference – gtk_drawing_area_set_draw_func</a>.</li>
</ul>
<p>The drawing function has five parameters.</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> drawing_function <span class="op">(</span>GtkDrawingArea <span class="op">*</span>drawing_area<span class="op">,</span> cairo_t <span class="op">*</span>cr<span class="op">,</span> <span class="dt">int</span> width<span class="op">,</span> <span class="dt">int</span> height<span class="op">,</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>                       gpointer user_data<span class="op">);</span></span></code></pre></div>
<p>The first parameter is the GtkDrawingArea widget. You can’t change
any properties, for example <code>content-width</code> or
<code>content-height</code>, in this function. The second parameter is a
cairo context given by the widget. The destination surface of the
context is connected to the contents of the widget. What you draw to
this surface will appear in the widget on the screen. The third and
fourth parameters are the size of the destination surface. Now, look at
the program again.</p>
<ul>
<li>3-17: The drawing function.</li>
<li>7-8: Sets the source to be white and paint the destination
white.</li>
<li>9: Sets the line width to be 2.</li>
<li>10: Sets the source to be black.</li>
<li>11-15: Adds a rectangle to the mask.</li>
<li>16: Draws the rectangle with black color to the destination.</li>
</ul>
<p>The program is src/misc/da1.c. Compile and run it, then a window with
a black rectangle (square) appears. Try resizing the window. The square
always appears at the center of the window because the drawing function
is invoked each time the window is resized.</p>
<figure>
<img src="image/da1.png" alt="Square in the window" />
<figcaption aria-hidden="true">Square in the window</figcaption>
</figure>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>
  </body>
  </html>
